module mycpu_top(
    input         aclk,
    input         aresetn,
    input         [5:0] int, 
    /*
    // inst sram interface
    output        inst_sram_req,
    output        inst_sram_wr,
    output [1:0]  inst_sram_size,
    output [3:0]  inst_sram_wstrb,
    output [31:0] inst_sram_addr,
    output [31:0] inst_sram_wdata,
    input         inst_sram_addr_ok,
    input         inst_sram_data_ok,
    input  [31:0] inst_sram_rdata,
    // data sram interface
    output        data_sram_req,
    output        data_sram_wr,
    output [1:0]  data_sram_size,
    output [3:0]  data_sram_wstrb,
    output [31:0] data_sram_addr,
    output [31:0] data_sram_wdata,
    input         data_sram_addr_ok,
    input         data_sram_data_ok,
    input  [31:0] data_sram_rdata,   */
    // trace debug interface

    //ar
    output [ 3:0] arid,
    output [31:0] araddr,
    output [ 7:0] arlen,
    output [ 2:0] arsize,
    output [ 1:0] arburst,
    output [ 1:0] arlock,
    output [ 3:0] arcache,
    output [ 2:0] arprot,
    output        arvalid,
    input         arready,
    //r
    input  [ 3:0] rid,
    input  [31:0] rdata,
    input  [ 1:0] rresp,
    input         rlast,
    input         rvalid,
    output        rready,
    //aw
    output [ 3:0] awid,
    output [31:0] awaddr,
    output [ 7:0] awlen,
    output [ 2:0] awsize,
    output [ 1:0] awburst,
    output [ 1:0] awlock,
    output [ 3:0] awcache,
    output [ 2:0] awprot,
    output        awvalid,
    input         awready,
    //w
    output [ 3:0] wid,
    output [31:0] wdata,
    output [ 3:0] wstrb,
    output        wlast,
    output        wvalid,
    input         wready,
    //b
    input  [ 3:0] bid,
    input  [ 1:0] bresp,
    input         bvalid,
    output        bready,



    output [31:0] debug_wb_pc,
    output [ 3:0] debug_wb_rf_wen,
    output [ 4:0] debug_wb_rf_wnum,
    output [31:0] debug_wb_rf_wdata
);
wire         clk;
assign     clk = aclk;
wire resetn;
assign resetn = aresetn;
reg         reset;
always @(posedge clk) reset <= ~aresetn;



wire inst_sram_req;
wire inst_sram_wr;
wire [1:0] inst_sram_size;
wire [3:0] inst_sram_wstrb;
wire [31:0] inst_sram_addr;
wire [31:0] inst_sram_wdata;
wire [31:0] inst_sram_rdata;
wire inst_sram_addr_ok;
wire inst_sram_data_ok;



wire data_sram_req;
wire data_sram_wr;
wire [1:0] data_sram_size;
wire [3:0] data_sram_wstrb;
wire [31:0] data_sram_addr;
wire [31:0] data_sram_wdata;
wire [31:0] data_sram_rdata;
wire data_sram_addr_ok;
wire data_sram_data_ok;


wire         ds_allowin;
wire         es_allowin;
wire         ms_allowin;
wire         ws_allowin;
wire         fs_to_ds_valid;
wire         ds_to_es_valid;
wire         es_to_ms_valid;
wire         ms_to_ws_valid;
wire [`FS_TO_DS_BUS_WD -1:0] fs_to_ds_bus;
wire [`DS_TO_ES_BUS_WD -1:0] ds_to_es_bus;
wire [`ES_TO_MS_BUS_WD -1:0] es_to_ms_bus;
wire [`MS_TO_WS_BUS_WD -1:0] ms_to_ws_bus;
wire [`WS_TO_RF_BUS_WD -1:0] ws_to_rf_bus;
wire [`BR_BUS_WD       -1:0] br_bus;
wire [`ES_TO_DS_BUS_WD -1:0] es_to_ds_bus;
wire [`MS_TO_DS_BUS_WD -1:0] ms_to_ds_bus;
wire [`WS_TO_FS_BUS_WD -1:0] ws_to_fs_bus;
wire [`WS_TO_CR_BUS_WD -1:0] ws_to_cr_bus;

wire    [63:0] mulresult;
wire    flush;
wire    [31:0]c0_rdata;
wire    ms_ex;
wire    ms_flush;
wire    ms_inst_mtc0;

wire found;
wire op_tlbp;
wire op_tlbwi;
wire op_tlbr;
wire [3:0]cw_index;
wire [7:0]c0_asid;
wire [18:0]c0_vpn2;
wire [19:0]c0_pfn0;
wire [2:0]c0_c0;
wire c0_d0;
wire c0_v0;
wire c0_g0;
wire [19:0]c0_pfn1;
wire [2:0]c0_c1;
wire c0_d1;
wire c0_v1;
wire c0_g1;
wire [3:0]c0_index;
wire  interrupt;

wire [18:0]s0_vpn2;
wire s0_odd_page;
wire [7:0]s0_asid;
wire s0_found;
wire [3:0]s0_index;
wire [19:0]s0_pfn;
wire [2:0]s0_c;
wire s0_d;
wire s0_v;
wire [18:0]s1_vpn2;
wire s1_odd_page;
wire [7:0]s1_asid;
wire s1_found;
wire [3:0]s1_index;
wire [19:0]s1_pfn;
wire [2:0]s1_c;
wire s1_d;
wire s1_v;
wire [18:0]r_vpn2;
wire [7:0]r_asid;
wire r_g;
wire [19:0]r_pfn0;
wire [2:0]r_c0;
wire r_d0;
wire r_v0;
wire [19:0]r_pfn1;
wire [2:0]r_c1;
wire r_d1;
wire r_v1;
wire inst_sram_req_p;
wire [31:0]inst_sram_addr_p;
wire data_sram_req_p;
wire [31:0]data_sram_addr_p;
wire inst_kseg0;
wire inst_kseg1;
wire inst_kseg23;
wire inst_kuseg;
wire data_kseg0;
wire data_kseg1;
wire data_kseg23;
wire data_kuseg;
wire ex_store;
wire [31:0]ms_pc;



cpu_axi_interface cpu_axi_interface(
    .clk          (clk        ),
    .reset        (reset     ),
        
    .inst_sram_req     (inst_sram_req_p  ),
    .inst_sram_wr      (inst_sram_wr     ),
    .inst_sram_wstrb   (inst_sram_wstrb  ),
    .inst_sram_size    (inst_sram_size   ),
    .inst_sram_addr    (inst_sram_addr_p ),
    .inst_sram_wdata   (inst_sram_wdata  ),
    .inst_sram_rdata   (inst_sram_rdata  ),
    .inst_sram_addr_ok (inst_sram_addr_ok),
    .inst_sram_data_ok (inst_sram_data_ok),

    .data_sram_req     (data_sram_req_p  ),
    .data_sram_wr      (data_sram_wr     ),
    .data_sram_wstrb   (data_sram_wstrb  ),
    .data_sram_size    (data_sram_size   ),
    .data_sram_addr    (data_sram_addr_p ),
    .data_sram_wdata   (data_sram_wdata  ),
    .data_sram_rdata   (data_sram_rdata  ),
    .data_sram_addr_ok (data_sram_addr_ok),
    .data_sram_data_ok (data_sram_data_ok),

    .arid         (arid        ),
    .araddr       (araddr      ),
    .arlen        (arlen       ),
    .arsize       (arsize      ),
    .arburst      (arburst     ),
    .arlock       (arlock      ),
    .arcache      (arcache     ),
    .arprot       (arprot      ),
    .arvalid      (arvalid     ),
    .arready      (arready     ),
        
    .rid          (rid         ),
    .rdata        (rdata       ),
    .rresp        (rresp       ),
    .rlast        (rlast       ),
    .rvalid       (rvalid      ),
    .rready       (rready      ),
        
    .awid         (awid        ),
    .awaddr       (awaddr      ),
    .awlen        (awlen       ),
    .awsize       (awsize      ),
    .awburst      (awburst     ),
    .awlock       (awlock      ),
    .awcache      (awcache     ),
    .awprot       (awprot      ),
    .awvalid      (awvalid     ),
    .awready      (awready     ),
        
    .wid          (wid         ),
    .wdata        (wdata       ),
    .wstrb        (wstrb       ),
    .wlast        (wlast       ),
    .wvalid       (wvalid      ),
    .wready       (wready      ),
        
    .bid          (bid         ),
    .bresp        (bresp       ),
    .bvalid       (bvalid      ),
    .bready       (bready      )
    );

// IF stage
if_stage if_stage(
    .clk            (clk            ),
    .reset          (reset          ),
    .flush          (flush          ),
    //allowin
    .ds_allowin     (ds_allowin     ),
    //brbus
    .br_bus         (br_bus         ),
    //outputs
    .fs_to_ds_valid (fs_to_ds_valid ),
    .fs_to_ds_bus   (fs_to_ds_bus   ),
    //from ws
    .ws_to_fs_bus   (ws_to_fs_bus   ),
    //from ms
    .ms_pc          (ms_pc          ),
    //tlb
    .tlb_found((inst_kseg23|inst_kuseg)?s0_found:1'b1),
    .tlb_valid((inst_kseg23|inst_kuseg)?s0_v:1'b1),
    // inst sram interface
    .inst_sram_req     (inst_sram_req),
    .inst_sram_wr      (inst_sram_wr),
    .inst_sram_size    (inst_sram_size),
    .inst_sram_wstrb   (inst_sram_wstrb),
    .inst_sram_addr    (inst_sram_addr),
    .inst_sram_wdata   (inst_sram_wdata),
    .inst_sram_addr_ok (inst_sram_addr_ok),
    .inst_sram_data_ok (inst_sram_data_ok),
    .inst_sram_rdata   (inst_sram_rdata)
);
// ID stage
id_stage id_stage(
    .clk            (clk            ),
    .reset          (reset          ),
    .flush          (flush          ),
    //allowin
    .es_allowin     (es_allowin     ),
    .ds_allowin     (ds_allowin     ),
    //from es
    .es_to_ds_valid (es_to_ds_valid ),
    .es_to_ds_bus   (es_to_ds_bus   ),
    //from ms
    .ms_to_ds_valid (ms_to_ds_valid ),
    .ms_to_ds_bus   (ms_to_ds_bus   ),
    //from fs
    .fs_to_ds_valid (fs_to_ds_valid ),
    .fs_to_ds_bus   (fs_to_ds_bus   ),
    //to es
    .ds_to_es_valid (ds_to_es_valid ),
    .ds_to_es_bus   (ds_to_es_bus   ),
    //to fs
    .br_bus         (br_bus         ),
    //to rf: for write back
    .ws_to_rf_bus   (ws_to_rf_bus   ),
    .interrupt      (interrupt)
);
// EXE stage
exe_stage exe_stage(
    .clk            (clk            ),
    .reset          (reset          ),
    .flush          (flush          ),
    .ms_flush       (ms_flush       ),
    .ms_inst_mtc0   (ms_inst_mtc0   ),
    //allowin
    .ms_allowin     (ms_allowin     ),
    .es_allowin     (es_allowin     ),
    //from ds
    .ds_to_es_valid (ds_to_es_valid ),
    .ds_to_es_bus   (ds_to_es_bus   ),
    //to ms
    .es_to_ms_valid (es_to_ms_valid ),
    .es_to_ms_bus   (es_to_ms_bus   ),
    //to ds
    .es_to_ds_valid (es_to_ds_valid ),
    .es_to_ds_bus   (es_to_ds_bus   ),
    //tlb
    .tlb_found((data_kseg23|data_kuseg)?s1_found:1'b1),
    .tlb_valid((data_kseg23|data_kuseg)?s1_v:1'b1),
    .tlb_dirty((data_kseg23|data_kuseg)?s1_d:1'b1),
    .ex_store(ex_store),
    // data sram interface
    .data_sram_req     (data_sram_req),
    .data_sram_wr      (data_sram_wr),
    .data_sram_size    (data_sram_size),
    .data_sram_wstrb   (data_sram_wstrb),
    .data_sram_addr    (data_sram_addr),
    .data_sram_wdata   (data_sram_wdata),
    .data_sram_addr_ok (data_sram_addr_ok),
    .mulresult (mulresult),
    .op_tlbp (op_tlbp)
);
// MEM stage
mem_stage mem_stage(
    .clk            (clk            ),
    .reset          (reset          ),
    .flush          (flush          ),
    //allowin
    .ws_allowin     (ws_allowin     ),
    .ms_allowin     (ms_allowin     ),
    .ms_flush       (ms_flush       ),
    .ms_inst_mtc0_v   (ms_inst_mtc0   ),
    //from es
    .es_to_ms_valid (es_to_ms_valid ),
    .es_to_ms_bus   (es_to_ms_bus   ),
    //to ds
    .ms_to_ds_valid (ms_to_ds_valid ),
    .ms_to_ds_bus   (ms_to_ds_bus   ),
    //to ws
    .ms_to_ws_valid (ms_to_ws_valid ),
    .ms_to_ws_bus   (ms_to_ws_bus   ),
    //to fs
    .ms_pc          (ms_pc          ),
    //from data-sram
    .data_sram_data_ok (data_sram_data_ok),
    .data_sram_rdata(data_sram_rdata),
    .mulresult(mulresult)
);
// WB stage
wb_stage wb_stage(
    .clk            (clk            ),
    .reset          (reset          ),
    .flush          (flush          ),
    //allowin
    .ws_allowin     (ws_allowin     ),
    //from ms
    .ms_to_ws_valid (ms_to_ws_valid ),
    .ms_to_ws_bus   (ms_to_ws_bus   ),
    //from cp0
    .c0_rdata       (c0_rdata       ),
    //to rf: for write back
    .ws_to_rf_bus   (ws_to_rf_bus   ),
    //to fs
    .ws_to_fs_bus   (ws_to_fs_bus   ),
    //to cp0
    .ws_to_cr_bus   (ws_to_cr_bus   ),
    //trace debug interface
    .debug_wb_pc      (debug_wb_pc      ),
    .debug_wb_rf_wen  (debug_wb_rf_wen  ),
    .debug_wb_rf_wnum (debug_wb_rf_wnum ),
    .debug_wb_rf_wdata(debug_wb_rf_wdata),
    .int(int),
    .op_tlbwi(op_tlbwi),
    .op_tlbr(op_tlbr)
);
// CP0 regs
cp0_regs cp0_regs(
		.clk            (clk            ),
		.reset          (reset          ),
		.ws_to_cr_bus   (ws_to_cr_bus   ),
        .found          (s1_found          ),
        .op_tlbp        (op_tlbp        ),
        .op_tlbwi       (op_tlbwi        ),
        .op_tlbr        (op_tlbr         ),
        /* tlbr logic*/ 
        .cw_asid        (r_asid         ),  
        .cw_vpn2        (r_vpn2         ),     
        .cw_pfn0        (r_pfn0         ),     
        .cw_c0          (r_c0           ),     
        .cw_d0          (r_d0           ), 
        .cw_v0          (r_v0           ),
        .cw_g0          (r_g            ),     
        .cw_pfn1        (r_pfn1         ),     
        .cw_c1          (r_c1           ),     
        .cw_d1          (r_d1           ),     
        .cw_v1          (r_v1           ),
        .cw_g1          (r_g            ),
        .cw_index       (cw_index       ),
        .c0_rdata       (c0_rdata       ),
        /* tlbwi logic*/ 
        .c0_asid        (c0_asid         ),  
        .c0_vpn2        (c0_vpn2         ),     
        .c0_pfn0        (c0_pfn0         ),     
        .c0_c0          (c0_c0           ),     
        .c0_d0          (c0_d0           ), 
        .c0_v0          (c0_v0           ),
        .c0_g0          (c0_g0            ),     
        .c0_pfn1        (c0_pfn1         ),     
        .c0_c1          (c0_c1           ),     
        .c0_d1          (c0_d1           ),     
        .c0_v1          (c0_v1           ),
        .c0_g1          (c0_g1           ),
        .c0_index       (c0_index        ),
        .interrupt      (interrupt      )
);

tlb tlb(
     .clk            (clk            ),
    // search port 0
     .s0_vpn2        (s0_vpn2        ),
     .s0_odd_page    (s0_odd_page    ),
     .s0_asid        (c0_asid        ),     
     .s0_found       (s0_found       ),     
     .s0_index       (s0_index       ),     
     .s0_pfn         (s0_pfn         ),     
     .s0_c           (s0_c           ),     
     .s0_d           (s0_d           ),     
     .s0_v           (s0_v           ), 
 
    // search port 1     
     .s1_vpn2        (s1_vpn2        ),
     .s1_odd_page    (s1_odd_page    ),
     .s1_asid        (c0_asid        ),     
     .s1_found       (s1_found       ),     
     .s1_index       (s1_index       ),     
     .s1_pfn         (s1_pfn         ),     
     .s1_c           (s1_c           ),     
     .s1_d           (s1_d           ),     
     .s1_v           (s1_v           ), 
    /* tlbwi logic*/ 
    // write port     
     .we             (op_tlbwi       ),      
     .w_index        (c0_index        ),     
     .w_vpn2         (c0_vpn2         ),     
     .w_asid         (c0_asid         ),     
     .w_g            (c0_g0& c0_g1    ),     
     .w_pfn0         (c0_pfn0         ),     
     .w_c0           (c0_c0           ),     
     .w_d0           (c0_d0           ), 
     .w_v0           (c0_v0           ),     
     .w_pfn1         (c0_pfn1         ),     
     .w_c1           (c0_c1           ),     
     .w_d1           (c0_d1           ),     
     .w_v1           (c0_v1           ), 
     
     // read port     
     .r_index        (c0_index        ),     
     .r_vpn2         (r_vpn2         ),     
     .r_asid         (r_asid         ),     
     .r_g            (r_g            ),     
     .r_pfn0         (r_pfn0         ),     
     .r_c0           (r_c0           ),     
     .r_d0           (r_d0           ), 
     .r_v0           (r_v0           ),     
     .r_pfn1         (r_pfn1         ),     
     .r_c1           (r_c1           ),     
     .r_d1           (r_d1           ),     
     .r_v1           (r_v1           )
     ); 

/* tlbp logic*/ 
/* address transfer*/
assign data_kseg0 = (data_sram_addr[31:29] == 3'b100) ;
assign data_kseg1 = (data_sram_addr[31:29] == 3'b101 );
assign data_kseg23 = (data_sram_addr[31:30] == 2'b11 );
assign data_kuseg = ~data_sram_addr[31];

assign s1_vpn2=(op_tlbp)?c0_vpn2:data_sram_addr[31:13];
assign s1_odd_page=(op_tlbp)?0:data_sram_addr[12];
assign data_sram_req_p=data_sram_req&((data_kseg23|data_kuseg)?s1_found & s1_v &~(~s1_d & ex_store):1'b1);
assign data_sram_addr_p=(data_kseg23|data_kuseg)?{s1_pfn,data_sram_addr[11:0]}:{3'b000,data_sram_addr[28:0]};
assign cw_index=s1_index;

/*fetch address transfer*/
assign inst_kseg0 = (inst_sram_addr[31:29] == 3'b100) ;
assign inst_kseg1 = (inst_sram_addr[31:29] == 3'b101) ;
assign inst_kseg23 = (inst_sram_addr[31:30] == 2'b11) ;
assign inst_kuseg = ~inst_sram_addr[31];

assign s0_vpn2=inst_sram_addr[31:13];
assign s0_odd_page=inst_sram_addr[12];
assign inst_sram_req_p = inst_sram_req&((inst_kseg23|inst_kuseg)?  s0_found & s0_v:1'b1);
assign inst_sram_addr_p = (inst_kseg23|inst_kuseg)?{s0_pfn,inst_sram_addr[11:0]}:{3'b000,inst_sram_addr[28:0]};




endmodule
